iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0

環境

OS: Windows 10
Editor: Visual Studio Code
Rust version: 1.63.0

泛型

今天簡單了解一下Rust中的泛型,真的是簡單而已,因為後面還有一個看整天感覺熟悉,但又很陌生的功能-特徵(trait),但以下的內容還是會牽扯到特徵的功能。

泛型函式

如同其他語言,在邏輯上可能做一樣的事,例如比大小找出最大值,但因為型別不同需要,寫出出各自的版本,這時就會使用泛型。

以找出序列中的最大值為例,這是範例資料:

let list = vec![2.0, 2.5, 1.0, 0.9, 3.2];
let max_in_list = max(&list);
println!("Max in list: {}", max_in_list);

這是功能實作

fn max<T>(list: &[T]) -> T {
    let mut max = list[0];
    for &item in list {
        if item > max {
            max = item;
        }
    }

    max
}

執行的會,compiler會丟出一段錯誤:

Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0369]: binary operation `>` cannot be applied to type `T`
  --> src\main.rs:36:17
   |
36 |         if item > max {
   |            ---- ^ --- T
   |            |
   |            T
   |
help: consider restricting type parameter `T`
   |
33 | fn max<T: std::cmp::PartialOrd>(list: &[T]) -> T {
   |         ++++++++++++++++++++++

For more information about this error, try `rustc --explain E0369`.

內容是說,如果要比大小,泛型的型別是要有實作>符號,也就是錯誤訊息提到的std::cmp::PartialOrd特徵

所以改成這樣,有點像C#where來限制可用的型別:

fn max<T: PartialOrd>(list: &[T]) -> T {
    let mut max = list[0];
    for &item in list {
        if item > max {
            max = item;
        }
    }

    max
}

但還是會跟你抱怨錯誤:

Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0508]: cannot move out of type `[T]`, a non-copy slice
  --> src\main.rs:34:19
   |
34 |     let mut max = list[0];
   |                   ^^^^^^^
   |                   |
   |                   cannot move out of here
   |                   move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait
   |                   help: consider borrowing here: `&list[0]`

error[E0507]: cannot move out of a shared reference
  --> src\main.rs:35:18
   |
35 |     for &item in list {
   |         -----    ^^^^
   |         ||
   |         |data moved here
   |         |move occurs because `item` has type `T`, which does not implement the `Copy` trait
   |         help: consider removing the `&`: `item`

Some errors have detailed explanations: E0507, E0508.
For more information about an error, try `rustc --explain E0507`.

compiler告訴我們,型別若沒有實作Copy,則資料的所有權會發生問題,我們就照compiler的建議,再加上限制,有實作Copy的型別才能使用,這時我們使用+來限制:

fn max<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut max = list[0];
    for &item in list {
        if item > max {
            max = item;
        }
    }

    max
}

泛型類別

之前就很常在用了,例如向量(vector)跟雜湊表(hash map)就是泛型的型別,下面示範如何定義泛型型別:

struct Point<T> {
    x: T,
    y: T,
}

如果要定義泛型型別的方法(methods):

impl<T> Point<T> {
    fn move_to(&mut self, nx: T, ny: T) {
        self.x = nx;
        self.y = ny;
    }
}

// example

let mut p = Point { x: 1.0, y: 2.0 };
p.move_to(15.0, 13.0);

然後,假如只指定一些泛型可以用,例如:

impl Point<bool> {
    fn reset(&mut self) {
        self.x = false;
        self.y = false;
    }
}

上面的例子就會是,當Point<T>是用bool型別的時候,才能使用reset

let mut pbool = Point { x: true, y: false };
pbool.reset();
let mut p = Point { x: 1.0, y: 2.0 };
p.reset();

錯誤訊息:

Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0599]: no method named `reset` found for struct `Point<{float}>` in the current scope
  --> src\main.rs:48:7
   |
3  | struct Point<T> {
   | --------------- method `reset` not found for this
...
48 |     p.reset();
   |       ^^^^^ method not found in `Point<{float}>`
   |
   = note: the method was found for
           - `Point<bool>`

For more information about this error, try `rustc --explain E0599`.

compiler會告訴你只有Point<bool>reset的實作。

Reference


上一篇
[Rust] 錯誤處理
下一篇
[Rust] 特徵 (Trait)
系列文
嘗試30天學「不」會Rust18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言